package com.happy3w.task.composer;

import lombok.Getter;
import lombok.Setter;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;

@Getter
public class TaskStatusHolder {
    private final long id;
    private final Task task;
    private List<TaskStatusHolder> depends;

    @Setter
    private TaskStatus status = TaskStatus.waiting;
    private Throwable throwable;
    private String message;

    public TaskStatusHolder(long id, Task task) {
        this.id = id;
        this.task = task;
    }

    public void configError(String message, Throwable throwable) {
        status = TaskStatus.failed;
        this.message = message;
        this.throwable = throwable;
    }

    public void addDepend(TaskStatusHolder dependHolder) {
        if (depends == null) {
            depends = new ArrayList<>();
        }
        for (TaskStatusHolder holder : depends) {
            if (holder.id == dependHolder.id) {
                return;
            }
        }
        depends.add(dependHolder);
    }

    public Stream<TaskStatusHolder> dependStream() {
        return depends == null ? Stream.empty() : depends.stream();
    }


    public static List<DependItem> genDependGraphItems(Collection<TaskStatusHolder> holderToShow) {

        Set<String> shouldAppearItems = new HashSet<>();
        Set<String> appearedItems = new HashSet<>();

        List<DependItem> dependItems = holderToShow.stream()
                .flatMap(task -> {
                    String from = task.getTask().outputNames();
                    shouldAppearItems.add(from);
                    return task.dependStream()
                            .map(depend -> {
                                String to = depend.getTask().outputNames();
                                appearedItems.add(from);
                                appearedItems.add(to);
                                return new DependItem(from, depend.getTask().outputNames());
                            });
                })
                .collect(Collectors.toList());

        shouldAppearItems.removeAll(appearedItems);
        shouldAppearItems.forEach(item -> {
            dependItems.add(new DependItem(item, item));
        });

        return dependItems;
    }

}
